package MAgentAssignment;

import MAgentAssignment.gui.InterfaceAgent;
import MAgentAssignment.ontology.FlightOntology;
import MAgentAssignment.ontology.FlightVocabulary;
import MAgentAssignment.ontology.actions.CloseAirport;
import MAgentAssignment.ontology.actions.CreateAirline;
import MAgentAssignment.ontology.actions.CreateAirpot;
import MAgentAssignment.ontology.actions.CreateNewFlight;
import MAgentAssignment.ontology.actions.CreatePlanes;
import MAgentAssignment.ontology.actions.Land;
import MAgentAssignment.ontology.concepts.Airline;
import MAgentAssignment.ontology.concepts.Airport;
import MAgentAssignment.ontology.concepts.Flight;
import MAgentAssignment.ontology.concepts.Location;
import MAgentAssignment.ontology.concepts.Plane;
import MAgentAssignment.ontology.concepts.Speed;
import examples.yellowPages.DFRegisterAgent;
import jade.content.lang.Codec;
import jade.content.lang.sl.SLCodec;
import jade.content.onto.Ontology;
import jade.core.AID;
import jade.core.Agent;
import jade.core.Service;
import jade.core.behaviours.CyclicBehaviour;
import jade.core.behaviours.OneShotBehaviour;
import jade.core.behaviours.TickerBehaviour;
import jade.domain.DFService;
import jade.domain.FIPAAgentManagement.DFAgentDescription;
import jade.domain.FIPAAgentManagement.ServiceDescription;
import jade.domain.FIPAException;
import jade.domain.introspection.AddedBehaviour;
import jade.lang.acl.ACLMessage;
import jade.lang.acl.MessageTemplate;
import jade.lang.acl.UnreadableException;
import jade.wrapper.AgentContainer;
import jade.wrapper.AgentController;
import jade.wrapper.StaleProxyException;

import java.io.IOException;
import java.util.Hashtable;
import java.util.Vector;

/**
 * Created by IntelliJ IDEA.
 * User: prageeth
 * Date: 2/16/12
 * Time: 2:25 PM
 * To change this template use File | Settings | File Templates.
 */
public class AirlineManagerAgent extends Agent
{
    private Codec codec = new SLCodec();
    private Ontology ontology = FlightOntology.getInstance();
    private Airline airline;
    private AgentController agentController;
    private Vector<Flight> flightsQueue = new Vector<Flight>();
    private Vector<Flight> waitingFlightQueue = new Vector<Flight>();
    private Hashtable<String, Airport> agentNameAndAirports = new Hashtable<String, Airport>();
    TickerBehaviour airportQueryBehaviouse = null;
    private int agentGenCounter = 0;
    //    private Hashtable<String, AgentController> flightAgentControlers = new Hashtable<String, AgentController>();

    @Override protected void setup()
    {
        // check current status
        // check landed flights
        // kill landed flights
        // how many flights can be generated
        // contact airplane agents to get the list of valid airplanes
        // create new flights
        // validate with airport managers
        // create flight agents

        getContentManager().registerLanguage( codec );
        getContentManager().registerOntology( ontology );
        ServiceDescription sd = new ServiceDescription();
        sd.setType( "AIRLINE" );
        sd.setName( getLocalName() );
        DFAgentDescription dfd = new DFAgentDescription();
        dfd.setName( getAID() );
        dfd.addServices( sd );
        try
        {
            DFService.register( this, dfd );
        }
        catch( FIPAException fe )
        {
            fe.printStackTrace();
        }
        Object[] args = getArguments();
        if( args != null && args[0] != null && args[0] instanceof Airline )
        {
            airline = (Airline) args[0];
        }

        addBehaviour( new CyclicBehaviour()
        {
            @Override public void action()
            {
                ACLMessage msg = receive( MessageTemplate.MatchPerformative( ACLMessage.INFORM ) );

                if( msg != null )
                {
                    if( msg.getContent() != null )
                    {
                        if( msg.getContent().equals( FlightVocabulary.AIRLINE_CLOSED ) )
                        {
                            airline = null;
                            block();
                        }
                        else
                        {
                            String flightNo = msg.getContent();
                            Flight foundFlight = null;
                            for( Flight flight : flightsQueue )
                            {
                                if( flight.getFlightNo().equals( flightNo ) )
                                {
                                    System.out.println( "Flight landed found" );
                                    foundFlight = flight;
                                    break;
                                }
                            }
                            if( foundFlight != null )
                            {
                                flightsQueue.remove( foundFlight );
                                System.out.println( "creating new flights for the landed one" );
                                waitingFlightQueue.add( foundFlight );
                                for( Airport airport : agentNameAndAirports.values() )
                                {
                                    if( airport.getAirpotCode().equals( foundFlight.getToAirport().getAirpotCode() ) )
                                    {
                                        airport.getIncomingFlights().remove( foundFlight );
                                        airport.getStayFlight().add( foundFlight );
                                        break;
                                    }
                                }
                                return;
                            }
                        }
                    }

                    {

                        Object contentObj = null;
                        try
                        {
                            contentObj = msg.getContentObject();
                        }
                        catch( UnreadableException e )
                        {
                            //                            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
                        }
                        if( contentObj != null )
                        {
                            if( contentObj instanceof CreateAirline )
                            {
                                CreateAirline createAirline = (CreateAirline) contentObj;
                                airline = createAirline.getAirline();
                                addBehaviour( new OneShotBehaviour()
                                {
                                    @Override public void action()
                                    {
                                        ACLMessage msg = new ACLMessage( ACLMessage.INFORM );
                                        msg.setLanguage( codec.getName() );
                                        try
                                        {
                                            CreateAirline createAirline = new CreateAirline();
                                            createAirline.setAirline( airline );
                                            msg.setContentObject( createAirline );
                                        }
                                        catch( IOException e )
                                        {
                                            e.printStackTrace();
                                        }

                                        msg.addReceiver( new AID( InterfaceAgent.agentName, AID.ISLOCALNAME ) );
                                        //no use of sending this so this will not send
                                        //                                    send( msg );
                                    }
                                } );
                            }
                            else if( contentObj instanceof CreateAirpot )
                            {
                                String agentName = msg.getSender().getLocalName();
                                CreateAirpot createAirpot = (CreateAirpot) contentObj;
                                Airport airport = createAirpot.getAirport();
                                if( airport != null )
                                {
                                    agentNameAndAirports.put( agentName, airport );
                                }

                            }
                            else if( contentObj instanceof CloseAirport )
                            {
                                String agentName = msg.getSender().getLocalName();
                                CloseAirport closeAirport = (CloseAirport) contentObj;
                                Airport airport = closeAirport.getAirport();
                                if( airport != null )
                                {
                                    agentNameAndAirports.remove( agentName );
                                }
                            }
                            else if( contentObj instanceof CreatePlanes )
                            {
                                createPlanes();
                            }
                            else if( contentObj instanceof Land )
                            {
                                Land land = (Land) contentObj;
                                Flight flight = land.getFlight();
                                if( flight.getFlightNo().startsWith( airline.getAirLineCode() ) )
                                {
                                    for( int i = 0; i < flightsQueue.size(); i++ )
                                    {
                                        Flight quedFlight = flightsQueue.get( i );
                                        if( quedFlight.getFlightNo().equals( flight.getFlightNo() ) )
                                        {
                                            flightsQueue.remove( quedFlight );
                                            i--;
                                            waitingFlightQueue.add( quedFlight );
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        } );

        addBehaviour( new TickerBehaviour( this, 1000 )
        {
            boolean initialSetuped = false;

            @Override protected void onTick()
            {
                if( airline != null )
                {
                    if( airline.getPlanes() == null || airline.getPlanes().isEmpty() )
                    {
                        createPlanes();
                    }
                    if( !initialSetuped && flightsQueue.size() <= airline.getMaxNumberOfFlight() )
                    {
                        for( Airport airport : agentNameAndAirports.values() )
                        {
                            for( Airport airport1 : agentNameAndAirports.values() )
                            {
                                if( airport != airport1 )
                                {
                                    Plane plane = airline.getPlanes().firstElement();
                                    if( validateRoute( airport, airport1, plane ) )
                                    {
                                        createFlight( airport, airport1, plane );
                                        initialSetuped = true;
                                    }
                                }
                                if( flightsQueue.size() > airline.getMaxNumberOfFlight() )
                                {
                                    break;
                                }
                            }
                            if( flightsQueue.size() > airline.getMaxNumberOfFlight() )
                            {
                                break;
                            }
                        }
                        if(agentNameAndAirports.isEmpty())
                        {
                          addBehaviour( airportQueryBehaviouse );
                        }
                    }
                    else
                    {
                        createContinueFlight();
                    }
                    // Perform the reque

                }
            }
        } );
        airportQueryBehaviouse = new TickerBehaviour( this, 1 )
        {
            @Override protected void onTick()
            {
                DFAgentDescription template = new DFAgentDescription();
                ServiceDescription sd = new ServiceDescription();
                sd.setType( "AIRPORT" );
                template.addServices( sd );
                try
                {
                    DFAgentDescription[] result = DFService.search( myAgent, template );
                    for( DFAgentDescription dfAgentDescription : result )
                    {
                        ACLMessage msg = new ACLMessage( ACLMessage.REQUEST );
                        msg.setContent( FlightVocabulary.WHAT_IS_THE_AIRPORT );
                        msg.addReceiver( new AID( dfAgentDescription.getName().getLocalName(), AID.ISLOCALNAME ) );
                        send( msg );
                    }
                }
                catch( FIPAException fe )
                {
                    fe.printStackTrace();
                }
                stop();
            }
        };


    }

    private void createPlanes()
    {
        if( airline != null )
        {
            for( int i = 0; i < airline.getMaxNumberOfFlight(); i++ )
            {
                if( airline.getPlanes().size() > i )
                {
                    continue;
                }
                Plane plane = new Plane();
                plane.setAirline( airline );
                plane.setPlaneType( "30" + i );
                plane.setLocation( new Location( 0, 0 ) );
                plane.setFuelTimeRatio( 10 );
                plane.setMaxPassengers( 400 );
                plane.setFuelCapacity( 500 );
                plane.setMaxSpeed( 10 );
                plane.setInAir( false );
                airline.getPlanes().add( plane );
            }
        }
    }

    private void createFlightAgent( Flight flight )
    {
        try
        {
            AgentContainer container = (AgentContainer) getContainerController(); // get a container controller for creating new agents
            //            try
            //            {
            //                Thread.sleep( 100 );
            //            }
            //            catch( InterruptedException e )
            //            {
            //                e.printStackTrace();
            //            }
            agentGenCounter++;

            synchronized( flight )
            {
                String flightName = "Flight : " + flight.getFlightNo() + ":" + agentGenCounter;
                System.out.println( "CCCCC:::Before creating flight aggent : " + flightName );
                agentController = container.createNewAgent( flightName, "MAgentAssignment.FlightAgent", null );
                flight.setAgentName( flightName );
                //            flightAgentControlers.put( flight.getFlightNo(), agentController );
                agentController.start();

                System.out.println( "SSSS:::Before Sending flight msges : " + flightName );

                ACLMessage msg = new ACLMessage( ACLMessage.INFORM );
                CreateNewFlight createFlight = new CreateNewFlight();
                createFlight.setFlight( flight );
                try
                {
                    msg.setContentObject( createFlight );
                }
                catch( IOException e )
                {
                    e.printStackTrace();
                }
                msg.addReceiver( new AID( flightName, AID.ISLOCALNAME ) );
                send( msg );
                for( Airport airport : agentNameAndAirports.values() )
                {
                    if( airport.getAirpotCode().equals( flight.getFromAirport().getAirpotCode() ) )
                    {
                        airport.getStayFlight().remove( flight );
                    }
                    if( airport.getAirpotCode().equals( flight.getToAirport().getAirpotCode() ) )
                    {
                        airport.getIncomingFlights().add( flight );
                    }
                }
            }
        }
        catch( StaleProxyException e )
        {
            e.printStackTrace();
        }
    }

    public void createFlight( Airport fromAirpot, Airport toAirpot, Plane plane )
    {
        Flight flight = new Flight( airline.getAirLineCode() + ( flightsQueue.size() + 1 ) + System.currentTimeMillis() + ":" + agentGenCounter );
        flight.setPlane( plane );
        flight.setAirline( airline );
        flight.setFromAirport( fromAirpot );
        flight.setToAirport( toAirpot );
        flight.setMaxStayTimeinMillis( 200 );
        flight.setSpeed( new Speed() );
        flight.setMaxStayTimeinMillis( 100 );
        //        MAgentAssignment.AirlineManagerAgent.CreateFlightAgent createFlightAgent = new CreateFlightAgent( flight );
        flightsQueue.add( flight );
        createFlightAgent( flight );
        //        addBehaviour( createFlightAgent );
    }

    public void createContinueFlight()
    {
        for( int i = 0; i < waitingFlightQueue.size(); i++ )
        {
            Flight flight = waitingFlightQueue.get( i );
            Airport toAirport = null;
            Airport fromAirport = flight.getToAirport();
            Vector<Airport> validAirports = new Vector<Airport>();
            for( Airport airport : agentNameAndAirports.values() )
            {
                if( !fromAirport.getAirpotCode().equals( airport.getAirpotCode() ) )
                {
                    int availability = airport.getParkingSlots() - airport.getIncomingFlights().size() - airport.getStayFlight().size();
                    if( availability > 0 )
                    {
                        validAirports.add( airport );
                    }
                }
            }

            double minTax = Double.MAX_VALUE;
            for( Airport validAirport : validAirports )
            {
                if( minTax > validAirport._getTax() )
                {
                    toAirport = validAirport;
                    minTax = validAirport._getTax();
                }
            }

            if( toAirport != null )
            {
                createFlight( fromAirport, toAirport, flight.getPlane() );
                waitingFlightQueue.remove( flight );
                i--;
            }
        }
    }

    public boolean validateRoute( Airport fromAirpot, Airport toAirport, Plane plane )
    {
        return true;
    }

    public Airline getAirline()
    {
        return airline;
    }

    public void setAirline( Airline airline )
    {
        this.airline = airline;
    }


}

